
/**A rigid body. These are created via b2World.CreateBody.*/
public class b2Body extends b2AllocationGuard {

	public b2Body m_prev;
	public b2Body m_next;

	private b2BodyType type;
	private float gravityScale;
	private float linearDamping;
	private float angularDamping;
	private b2Vec2 m_linearVelocity;


	private b2World m_world;
	private b2Fixture m_fixtureList;
	private b2ContactEdge m_contactList;
	private b2JointList m_jointList;
	private b2Fixture m_fixtureList;

	private b2Transform m_xf;
	priavte b2Sweep m_sweep;

	public b2Body(int addr) {
		super(addr);

		m_xf = new b2Transform(jni_b2Body_GetTransform(address));
	}

	@Override
	public void release() {
		if ( address != 0 ) {
			jni_b2Body_release(address);

			// prevent release() be called on them.
			m_xf.address = 0;
			
		}
		super.release();
	}

	/**
	 * Creates a fixture and attach it to this body. Use this function if you need
	 * to set some fixture parameters, like friction. Otherwise you can create the
	 * fixture directly from a shape.
	 * If the density is non-zero, this function automatically updates the mass of the body.
	 * Contacts are not created until the next time step.
	 * @param def the fixture definition.
	 * @warning This function is locked during callbacks.
	**/
	public b2Fixture CreateFixture(final b2FixtureDef def) {
		int fixAddr = jni_b2Body_CreateFixture(def.address);

		b2Fixture fix = new b2Fixture(fixAddr);

		fix.m_next = m_fixtureList;
		m_fixtureList = fix;

		fix.m_body = this;

		return fix;
	}

	/**
	 * Creates a fixture from a shape and attach it to this body.
	 * This is a convenience function. Use b2FixtureDef if you need to set parameters
	 * like friction, restitution, user data, or filtering.
	 * If the density is non-zero, this function automatically updates the mass of the body.
	 * @param shape the shape to be cloned.
	 * @param density the shape density (set to zero for static bodies).
	 * @warning This function is locked during callbacks.
	**/
	public b2Fixture CreateFixture(final b2Shape shape, float density) {
		int fixAddr = jni_b2Body_CreateFixture2(shape.address, density);

		b2Fixture fix = new b2Fixture(fixAddr);
		fix.m_next = m_fixtureList;
		m_fixtureList = fix;
		fix.m_body = this;

		return fix;
	}

	/**
	 * Destroy a fixture. This removes the fixture from the broad-phase and
	 * destroys all contacts associated with this fixture. This will
	 * automatically adjust the mass of the body if the body is dynamic and the
	 * fixture has positive density.
	 * All fixtures attached to a body are implicitly destroyed when the body is destroyed.
	 * @param fixture the fixture to be removed.
	 * @warning This function is locked during callbacks.
	**/
	public void DestroyFixture(b2Fixture fixture) {
		jni_b2Body_DestroyFixture(address, fixture.address);

		// Remove the fixture from this body's singly linked list.
		b2Fixture fix = m_fixtureList;
		b2Fixture prev = null;

		while ( fix != null ) {
			if ( fix == fixture ) {
				if ( prev == null ) {
					m_fixtureList = fix.m_next;
					fix.address = 0; 
					break;
				}
				else {
					prev.m_next = fix.m_next;
					fix.address = 0;
					break;
				}
			}
			prev = fix;
			fix = fix.m_next;
		}
	}

	/**
	 * Set the position of the body's origin and rotation.
	 * This breaks any contacts and wakes the other bodies.
	 * Manipulating a body's transform may cause non-physical behavior.
	 * @param position the world position of the body's local origin.
	 * @param angle the world rotation in radians.
	**/
	public void SetTransform(final b2Vec2 position, float angle) {
		jni_b2Body_SetTransform(address, position.address, angle);
	}

	/**
	 * Get the body transform for the body's origin.
	 * @return the world transform of the body's origin.
	**/
	public b2Transform GetTransform() {
		return m_xf;
	}

	/**
	 * Get the world body origin position.
	 * @return the world position of the body's origin.
	**/
	public b2Vec2 GetPosition() {
		return m_xf.p;
	}

	/**
	 * Get the angle in radians.
	 * @return the current world rotation angle in radians.
	**/
	public float GetAngle() {
		return m_sweep.a;
	}

	/**
	 * Get the world position of the center of mass.
	**/
	public b2Vec2 GetWorldCenter() {
		
	}

	/**
	 * Get the local position of the center of mass.
	**/
	public b2Vec2 GetLocalCenter() {
		
	}

	/**
	 * Set the linear velocity of the center of mass.
	 * @param v the new linear velocity of the center of mass.
	**/
	public void SetLinearVelocity(b2Vec2 v) {
		m_linearVelocity = v;
		jni_b2Body_SetLinearVelocity(address, v.address);
	}

	/**
	 * Get the linear velocity of the center of mass.
	 * @return the linear velocity of the center of mass.
	**/
	public b2Vec2 GetLinearVelocity() {
		return m_linearVelocity;
	}

	/**
	 * Set the angular velocity.
	 * @param omega the new angular velocity in radians/second.
	**/
	public void SetAngularVelocity(float omega) {
		jni_b2Body_SetAngularVelocity(address, omega);
	}

	/**
	 * Get the angular velocity.
	 * @return the angular velocity in radians/second.
	**/
	public float GetAngularVelocity() {
		return jni_b2Body_GetAngularVelocity(address);
	}

	/**
	 * Apply a force at a world point. If the force is not
	 * applied at the center of mass, it will generate a torque and
	 * affect the angular velocity. This wakes up the body.
	 * @param force the world force vector, usually in Newtons (N).
	 * @param point the world position of the point of application.
	**/
	public void ApplyForce(final b2Vec2 force, final b2Vec2 point) {
		jni_b2Body_ApplyForce(address, force.address, point.address);
	}

	/**
	 * Apply a force to the center of mass. This wakes up the body.
	 * @param force the world force vector, usually in Newtons (N).
	**/
	public void ApplyForceToCenter(final b2Vec2 force) {
		jni_b2Body_ApplyForceToCenter(address, force.address);
	}

	/**
	 * Apply a torque. This affects the angular velocity
	 * without affecting the linear velocity of the center of mass.
	 * This wakes up the body.
	 * @param torque about the z-axis (out of the screen), usually in N-m.
	**/
	public void ApplyTorque(float torque) {
		jni_b2Body_ApplyTorque(address, torque);
	}

	/**
	 * Apply an impulse at a point. This immediately modifies the velocity.
	 * It also modifies the angular velocity if the point of application
	 * is not at the center of mass. This wakes up the body.
	 * @param impulse the world impulse vector, usually in N-seconds or kg-m/s.
	 * @param point the world position of the point of application.
	**/
	public void ApplyLinearImpulse(final b2Vec2 impulse, final b2Vec2 point) {
		jni_b2Body_ApplyLinearImpulse(address, impulse.address, point.address);
	}

	/**
	 * Apply an angular impulse.
	 * @param impulse the angular impulse in units of kg*m*m/s
	**/
	public void ApplyAngularImpulse(float impulse) {
		jni_b2Body_ApplyAngularImpulse(address, impulse);
	}

	/**
	 * Get the total mass of the body.
	 * @return the mass, usually in kilograms (kg).
	**/
	public float GetMass() {
		return jni_b2Body_GetMass(address);
	}

	/**
	 * Get the rotational inertia of the body about the local origin.
	 * @return the rotational inertia, usually in kg-m^2.
	**/
	public float GetInertia() {
		return jni_b2Body_GetInertia(address);
	}

	/**
	 * Get the mass data of the body.
	 * @return a struct containing the mass, inertia and center of the body.
	**/
	public void GetMassData(b2MassData data) {
		jni_b2Body_GetMassData(address, data.address);
	}

	/**
	 * Set the mass properties to override the mass properties of the fixtures.
	 * Note that this changes the center of mass position.
	 * Note that creating or destroying fixtures can also alter the mass.
	 * This function has no effect if the body isn't dynamic.
	 * @param massData the mass properties.
	**/
	public void SetMassData(final b2MassData data) {
		jni_b2Body_SetMassData(address, data.address);
	}

	/**
	 * This resets the mass properties to the sum of the mass properties of the fixtures.
	 * This normally does not need to be called unless you called SetMassData to override
	 * the mass and you later want to reset the mass.
	**/
	public void ResetMassData() {
		jni_b2Body_ResetMassData(address);
	}

	/**
	 * Get the world coordinates of a point given the local coordinates.
	 * @param localPoint a point on the body measured relative the the body's origin.
	 * @return the same point expressed in world coordinates.
	**/
	public b2Vec2 GetWorldPoint(final b2Vec2 localPoint) {
		//TODO: 要返回一个新的 b2Vec2 对象，且不能修改 localPoint 的内容
		// C/C++ 的实现是： 按值传参，返回一个临时对象
	}

	/**
	 * Get the world coordinates of a vector given the local coordinates.
	 * @param localVector a vector fixed in the body.
	 * @return the same vector expressed in world coordinates.
	**/
	public b2Vec2 GetWorldVector(final b2Vec2 localVector) {
		//TODO
	}

	/**
	 * Gets a local point relative to the body's origin given a world point.
	 * @param a point in world coordinates.
	 * @return the corresponding local point relative to the body's origin.
	**/
	public b2Vec2 GetLocalPoint(final b2Vec2 worldPoint) {
		//TODO
	}

	/**
	 * Gets a local vector given a world vector.
	 * @param a vector in world coordinates.
	 * @return the corresponding local vector.
	**/
	public b2Vec2 GetLocalVector(final b2Vec2 worldVector) {
		//TODO
	}

	/**
	 * Get the world linear velocity of a world point attached to this body.
	 * @param a point in world coordinates.
	 * @return the world velocity of a point.
	**/
	public b2Vec2 GetLinearVelocityFromWorldPoint(final b2Vec2 worldPoint) {
		//TODO
	}

	/**
	 * Get the world velocity of a local point.
	 * @param a point in local coordinates.
	 * @return the world velocity of a point.
	**/

	public b2Vec2 GetLinearVelocityFromLocalPoint(final b2Vec2 localPoint) {
		//TODO:
	}

	/**
	 * Get the linear damping of the body.
	**/
	public float GetLinearDamping() {
		return linearDamping;
	}

	/**
	 * Set the linear damping of the body.
	**/
	public void SetLinearDamping(float linearDamping) {
		this.linearDamping = linearDamping;
		jni_b2Body_SetLinearDamping(address, linearDamping);
	}

	/**
	 * Get the angular damping of the body.
	**/
	public float GetAngularDamping() {
		return angularDamping;
	}

	/**
	 * Set the angular damping of the body.
	**/
	public void SetAngularDamping(float angularDamping) {
		this.angularDamping = angularDamping;
		jni_b2Body_SetAngularDamping(address, angularDamping);
	}

	/**
	 * Get the gravity scale of the body.
	**/
	public float GetGravityScale() {
		return gravityScale;
	}

	/**
	 * Set the gravity scale of the body.
	**/
	public void SetGravityScale(float scale) {
		gravityScale = scale;
		jni_b2Body_SetGravityScale(address, scale);
	}
		

	/**
	 * Set the type of this body. This may alter the mass and velocity.
	**/
	public void SetType(b2BodyType type) {
		this.type = type;
		jni_b2Body_SetType(address, type.ordinal());
	}

	/**
	 * Get the type of this body.
	**/
	public b2BodyType GetType() {
		return type;
	}

	/**
	 * Should this body be treated like a bullet for continuous collision detection?
	**/
	public void SetBullet(boolean flag) {
		jni_b2Body_SetBullet(address, flag);
	}

	/**
	 * Is this body treated like a bullet for continuous collision detection?
	**/
	public boolean IsBullet() {
		return jni_b2Body_IsBullet(address);
	}

	/**
	 * You can disable sleeping on this body. If you disable sleeping, the
	 * body will be woken.
	**/
	public void SetSleepingAllowed(boolean flag) {
		jni_b2Body_SetSleepingAllowed(address, flag);
	}

	/**
	 * Is this body allowed to sleep
	**/
	public boolean IsSleepingAllowed() {
		return jni_b2Body_IsSleepingAllowed(address);
	}

	/**
	 * Set the sleep state of the body. A sleeping body has very
	 * low CPU cost.
	 * @param flag set to true to put body to sleep, false to wake it.
	**/
	public void SetAwake(boolean flag) {
		jni_b2Body_SetAwake(address, flag);
	}

	/**
	 * Get the sleeping state of this body.
	 * @return true if the body is sleeping.
	**/
	public boolean IsAwake() {
		return jni_b2Body_IsAwake(address);
	}

	/**
	 * Set the active state of the body. An inactive body is not
	 * simulated and cannot be collided with or woken up.
	 * If you pass a flag of true, all fixtures will be added to the
	 * broad-phase.
	 * If you pass a flag of false, all fixtures will be removed from
	 * the broad-phase and all contacts will be destroyed.
	 * Fixtures and joints are otherwise unaffected. You may continue
	 * to create/destroy fixtures and joints on inactive bodies.
	 * Fixtures on an inactive body are implicitly inactive and will
	 * not participate in collisions, ray-casts, or queries.
	 * Joints connected to an inactive body are implicitly inactive.
	 * An inactive body is still owned by a b2World object and remains
	 * in the body list.
	**/
	public void SetActive(boolean flag) {
		jni_b2Body_SetActive(address, flag);
	}

	/**
	 * Get the active state of the body.
	**/
	public boolean IsActive() {
		return jni_b2Body_IsActive(address);
	}

	/**
	 * Set this body to have fixed rotation. This causes the mass
	 * to be reset.
	**/
	public void SetFixedRotation(boolean flag) {
		jni_b2Body_SetFixedRotation(address, flag);
	}

	/**
	 * Does this body have fixed rotation?
	**/
	public boolean IsFixedRotation() {
		return jni_b2Body_IsFixedRotation(address);
	}

	/**
	 * Get the list of all fixtures attached to this body.
	**/
	public b2Fixture GetFixtureList() {
		return m_fixtureList;
	}

	/**
	 * Get the list of all joints attached to this body.
	**/
	public b2JointEdge GetJointList() {
		return m_jointList;
	}

	/**
	 * Get the list of all contacts attached to this body.
	 * @warning this list changes during the time step and you may
	 * miss some collisions if you don't use b2ContactListener.
	**/
	public b2ContactEdge GetContactList() {
		return m_contactList;
	}

	/**
	 * Get the next body in the world's body list.
	**/
	public b2Body GetNext() {
		return m_next;
	}

	/**
	 * Get the user data pointer that was provided in the body definition.
	**/
	public int GetUserData() {
		throw new UnsupportedOperationException();
	}

	/**
	 * Set the user data. Use this to store your application specific data.
	 * (NOT IMPLEMENTED YET)
	**/
	public void SetUserData(int data) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Get the parent world of this body.
	**/
	public b2World GetWorld() {
		return m_world;
	}

	/**
	 * Dump this body to a log file
	**/
	public void Dump() {
		jni_b2Body_Dump(address);
	}
}

